%%% Copyright [heng] [litaocheng@gmail.com] 
%%% Licensed under the Apache License, Version 2.0 (the "License");
%%% you may not use this file except in compliance with the License. 
%%% You may obtain a copy of the License at 
%%%    http://www.apache.org/licenses/LICENSE-2.0 
%%% Unless required by applicable law or agreed to in writing, 
%%% software distributed under the License is distributed on an "AS IS" BASIS, 
%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
%%% See the License for the specific language governing permissions and 
%%% limitations under the License. 

%% this module is used to report worker info to master
%% we use the gen_server timeout to send the report to master
%%      master                  worker
%%   ------------       ------------------------
%%  start worker  ----> reporter start link
%%                      parse the report setting
%%                <---- report the info interval
%%                <---- .......
%%  change reprot ----> change the report setting
%%                <---- reprot the info interval
%%                      .......
%%                      
-module(heng_worker_reporter).
-author('litaocheng@gmail.com').
-vsn('0.1').
-include("heng_worker.hrl").

-export([start_link/1]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
                            terminate/2, code_change/3]).
                            
-record(state, 
        {
           receiver,    % the receiver name on master
           master,      % the master node
           sesskey,     % report key from master
           setting      % some setting info
        }).
-define(SERVER, ?MODULE).

%% @doc start the reporter
start_link({Receiver, Master, SessKey} = Args) 
    when is_atom(Receiver) andalso is_atom(Master) ->
    gen_server:start_link({local, ?SERVER}, ?MODULE, Args, Master}, []).

%% gen_server callbacks
init({Receiver, Master, SessKey} = Args) ->    
    % start the 
    ?Debug("reporter start:~p", [Args]),
    State = #state{receiver = Receiver,
                    master = Master,
                    sesskey = SessKey
                },
    {ok, State}.

handle_call(_Msg, _From, State) ->
    {noreply, State}.

handle_cast({Ref, setting, Setting = #rep_setting{}}, State) ->
    State2 = State#state{setting = Setting},
    {noreply, State2, Setting#rep_setting.interval};
handle_cast(_Msg, State) ->
    {noreply, State}.

handle_info(timeout, State) -> % send the reprot info to master
    #state{receiver = Receiver,
            master = Master,
            sesskey = Sess,
            setting = Setting
            } = State,
    Reports = do_getreport(Setting),
    {Receiver, Master} ! {report, Sess, Reports},
    {noreply, State, Setting#rep_setting.interval};
handle_info(_Info, State) ->
    {noreply, State}.

terminate(_Reason, _State) ->
    ok.

code_change(_Old, State, _Extra) ->
    {ok, State}.


%%
%% internal API
%%

%% start the worker in a new process
do_start_worker(#workerr{name = Name, host = Host}, From, State) ->
    _Ref = make_ref(),
    _Connecter = 
    proc_lib:spawn_link(
        fun() ->
            case start_slave(Host, Name, "") of
                {ok, Node} ->
                    gen_server:reply(From, {ok, Node});
                {error, R} ->
                    ?Error("start slave node error:~p", [R]),
                    gen_server:reply(From, {error, R}
            end
        end
    ).

%% start the slave node
start_slave(Host, Name, Args) ->
    slave:start(Host, Name, Args).


%% get the report info
do_getreport(Setting) ->
    #rep_setting{
         mem = Mem,
         cpu = Cpu,
         disk = Disk,
         job = Job,
         alarm = Alarm
    } = Setting,
    RepList =
    [
        report_item(mem, Mem),
        report_item(cpu, Cpu),
        report_item(disk, Disk),
        report_item(job, Job),
        report_item(alarm, Alarm)
    ],

    list:flatten(RepList).

%% reprot one item
report_item(mem, 0) ->
    [];
report_item(mem, 1) ->
    {mem, []};

report_item(cpu, 0) ->
    [];
report_item(cpu, 1) ->
    {cpu, []};

report_item(disk, 0) ->
    [];
report_item(disk, 1) ->
    {disk, []};

report_item(job, 0) ->
    [];
report_item(job, 1) ->
    {job, []};

report_item(alarm, 0) ->
    [];
report_item(alarm, 1) ->
    {alarm, []}.
